#!/usr/bin/env python
# coding: utf-8

# <center><font size = "6">CNKI实践期末</font></center>  

# ## driver

# In[158]:


from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
import pandas as pd
import re
from lxml.html import fromstring
from requests_html import HTMLSession
import urllib.parse
import time
from random import random
import base64
import json
import requests

#caps=dict()
#caps["pageLoadStrategy"] = "none"   # Do not wait for full page load

opts = webdriver.ChromeOptions()
opts.add_argument('--no-sandbox')#解决DevToolsActivePort文件不存在的报错
opts.add_argument('window-size=1920x3000') #指定浏览器分辨率
opts.add_argument('--disable-gpu') #谷歌文档提到需要加上一这个属性来规避bug
opts.add_argument('--hide-scrollbars') #隐藏滚动条, 应对些特殊页面

driver = webdriver.Chrome( chrome_options = opts) #desired_capabilities=caps,


# ## 打开cnki
# * 1.校园网，自动登录 cnki.net
# * 2.校外网，需要登录fsso.cnki.net

# In[159]:


driver.get("https://www.cnki.net/")


# In[160]:


driver.find_element_by_id("Ecp_loginShowName1").get_attribute('innerHTML')


# ## 打开高级检索

# In[161]:


element=driver.find_element_by_id('highSearch')
element.get_attribute('innerHTML')
element.click()


# ## 查看窗口并切换窗口

# In[48]:


## 当前窗口
driver.current_window_handle


# In[49]:


# 查看所以窗口信息
driver.window_handles


# In[162]:


# 切换窗口
driver.switch_to_window(driver.window_handles[1])


# In[163]:


element=driver.find_element_by_xpath('/html/body/div[3]/div[1]/div/ul[1]/li[1]/a/span')
element.get_attribute('innerHTML')
element.click()


# ## 检索想要查看的文章内容

# In[164]:


# 专业检索
element=driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/ul/li[4]')
element.click()


# In[165]:


# 输入关键词
element=driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div/div[1]/div[1]/div[2]/textarea')
element.clear()
element.send_keys(' SU=“新媒体” AND SU=“设计”')


# In[166]:


# 检索
element=driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div/div[1]/div[1]/div[2]/div[2]/input')
element.click()


# ## 设置页面信息

# In[167]:


# 显示文章数量
driver.find_element_by_xpath('//*[@id="countPageDiv"]/span[1]/em').get_attribute('innerHTML')


# In[168]:


## 更换页面文章数量
element=driver.find_element_by_xpath('//*[@id="perPageDiv"]/div/i')
element.click()


# In[169]:


element=driver.find_element_by_xpath('//*[@id="perPageDiv"]/ul/li[3]/a')
element.click()


# In[170]:


## 查看单页面文章数量
driver.find_element_by_xpath('//*[@id="perPageDiv"]/div/span').get_attribute('innerHTML')


# ## 爬取页面基本信息

# In[87]:


## 抓取页面信息
element=driver.find_element_by_id('gridTable')
页面_表格_html=element.get_attribute('innerHTML')
首页主要数据 = pd.read_html(页面_表格_html)[0]
首页主要数据


# ## 获取详细页的链接并与基本信息表格合并

# In[60]:


# 解析页面获取链接
html=driver.page_source
root=fromstring(html)
href = [x for x in root.xpath('.//*[@id="gridTable"]/table/tbody/tr/td[2]/a/@href')]
# 将获取的链接改为正确的链接
c_link=['https://kns.cnki.net/kcms/detail/detail.aspx?'+x.split('&')[6]+'&'+x.split('&')[5]+'&'+x.split('&')[4] for x in href]
c_link


# In[61]:


links=[]
for link in c_link:
#     link=correct(link)
    links.append(link)
    df_links=pd.DataFrame({'页面链接':links})
    df_表格合并=pd.concat([pd.read_html(页面_表格_html)[0],df_links],axis=1)
df_表格合并  


# ## 获取详细页面pdf的下载链接

# In[62]:


pdf_links=[]
for url in c_link:
    session = HTMLSession()
    r = session.get( url )
    pdf_link_xpath=r.html.xpath('//*[@id="pdfDown"]/@href')[1]
    pdf_links.append(pdf_link_xpath)


# In[63]:


pdf_links


# In[64]:


## 修复正确的pdf下载链接
pdf_href=['https://kns.cnki.net'+link for link in pdf_links]
pdf_href


# ### 合并下载链接

# In[65]:


df_pdf_links=pd.DataFrame({'pdf下载':pdf_links})
df_表格合并=pd.concat([df_表格合并,df_pdf_links],axis=1)
df_表格合并


# ## 翻页

# In[72]:


# 翻页
element = driver.find_element_by_id('PageNext')
element.get_attribute('innerHTML')


# In[73]:


表格_html = dict()
main_content =""
element = None


# In[74]:


# 所有页数
pages = list(range(1,21))
print(pages)


# In[78]:


# 函数（翻页）
def process_pages (pages):
    for p in pages:
        print (p,end='\t')
        # 定位到“下一页”的按钮 ——> 点击
        跳转 = driver.find_element_by_id('PageNext')
        跳转.click()
        # 设定休息的时间 ——> 避免爬虫被禁报错、以及出现验证码
        time.sleep(30+20*random())
        # 获取含有页面主要数据的表格
        element = driver.find_element_by_id('gridTable')
        main_content = element.get_attribute('innerHTML')
        表格_html[p] = main_content


# In[79]:


# 翻页操作
process_pages(pages)


# In[82]:


df = pd.DataFrame([表格_html]).T
df.columns = ["html_snippets"]
display(df)


# In[83]:


l_df = []
for p in pages:
    表格 = pd.read_html(表格_html[p])[0]
    l_df.append(表格)


# In[88]:


# 获取全部页面（21页）内容信息
df_url_out = pd.concat(l_df).reset_index(drop=True)
df_总表 = 首页主要数据.append(df_url_out).reset_index()
df_总表


# ## 翻页获取全部详情页链接、pdf下载链接

# In[89]:


# 检查翻页后一共获取了 id为gridTable的标签
raw = [表格_html[p] for p in pages]
len(raw)


# In[90]:


# 解析 —— 详情页链接
root_group = []
for i in raw:
    root = fromstring(i)
    root_group.append(root)
print(len(root_group))

# 获取详情页链接
links_all = []
for j in root_group:
    links_all.extend(j.xpath('//table[@class="result-table-list"]/tbody//td[@class="name"]/a/@href'))
print(len(links_all))
links_all

# 将详情页链接修改成正确形式
all_correct_url = []
for i in links_all:
    b = i.replace('/KNS8/Detail?','https://kns.cnki.net/kcms/detail/detail.aspx?')
    all_correct_url.append(b)
all_correct_url


# In[92]:


# 合并链接 —— 与首页的链接合并得到全部链接 可通过检查长度 len(list_all_url) 得知是否正确
list_all_url = []
for item in c_link:
    list_all_url.append(item)
for item in all_correct_url:
    list_all_url.append(item)
list_all_url


# In[94]:


# 获取每篇文章的pdf下载链接
all_pdf_url = []
for i in all_correct_url:
    session = HTMLSession()
    r = session.get(i)
    all_pdf_url_xpath = r.html.xpath('//a[@id="pdfDown"]/@href')[0]
    all_pdf_url.append(all_pdf_url_xpath)
print(len(all_pdf_url))

# 将获取到的pdf链接改成正确的链接
all_pdf_correct_url = ['https://kns.cnki.net'+ link for link in all_pdf_url]
all_pdf_correct_url


# In[95]:


# 合并pdf链接
list_all_pdf_url = []
for item in pdf_href:
    list_all_pdf_url.append(item)
for item in all_pdf_correct_url:
    list_all_pdf_url.append(item)
list_all_pdf_url


# In[96]:


# 将获取到的详情页链接与pdf下载链接转换为表格
df_url = pd.DataFrame({'详情页链接':list_all_url,'pdf':list_all_pdf_url}).reset_index()
df_url


# In[97]:


# 合并表格【页面内容与链接】
df_all_information = pd.concat([df_总表,df_url],axis=1)
df_all_information


# In[98]:


# 将表格存到本地
with pd.ExcelWriter('CNKI数据.xlsx',mode='w',engine="openpyxl") as writer:  
            df_all_information.to_excel(writer,sheet_name="知网数据")


# ## 下载pdf部分

# In[143]:


# 准备工作
#caps=dict()
#caps["pageLoadStrategy"] = "none"   # Do not wait for full page load

opts = webdriver.ChromeOptions()
opts.add_argument('--no-sandbox')#解决DevToolsActivePort文件不存在的报错
opts.add_argument('window-size=1920x3000') #指定浏览器分辨率
opts.add_argument('--disable-gpu') #谷歌文档提到需要加上一这个属性来规避bug
opts.add_argument('--hide-scrollbars') #隐藏滚动条, 应对些特殊页面
#opts.add_argument('blink-settings=imagesEnabled=false') #不加载图片, 提升速度
#opts.add_argument('--headless') #浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败
# opts.binary_location = "C:\portable\PortableApps\IronPortable\App\Iron\chrome.exe"
# opts.binary_location = "C:\Program Files\Google\Chrome\Application\chromedriver.exe" #"H:\_coding_\Gitee\InternetNewMedia\CapstonePrj2016\chromedriver.exe"  


options = webdriver.ChromeOptions()
out_path = r'C:\Users\Downloads\cnki_pdf'  # 是你想指定的路径
prefs = {'profile.default_content_settings.popups': 0, 'download.default_directory': out_path}
options.add_experimental_option('prefs', prefs)
driver = webdriver.Chrome(executable_path=r'C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe', chrome_options=options)
#driver = webdriver.Chrome( chrome_options = opts) #desired_capabilities=caps


# In[131]:


def base64_api(uname, pwd, img, typeid):
    with open(img, 'rb') as f:
        base64_data = base64.b64encode(f.read())
        b64 = base64_data.decode()
    data = {"username": uname, "password": pwd, "typeid": typeid, "image": b64}
    result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text)
    if result['success']:
        return result["data"]["result"]
    else:
        return result["message"]
    return ""


# In[144]:


# 读取上面已保存在本地的xlsx文件【利用里面的pdf下载链接】
data = pd.read_excel("CNKI数据.xlsx") 
base = "https://kns.cnki.net/"
# 开始与结束的链接序号 count end_count
count = 421
end_count = 450 
# 读取title、pdf链接
title_list = data["篇名"].to_list()[count:end_count]
download_url_list = data["pdf"].to_list()[count:end_count]
list_all_url_list = data["详情页链接"].to_list()[count:end_count]
for title,download_url,list_all_url in zip(title_list,download_url_list,list_all_url_list):
    try:
        # 进入pdf的下载链接
        driver.get(download_url)
        time.sleep(5)
        # 出现验证码的情况
        if driver.find_element_by_xpath('//*[@id="vImg"]'):
            time.sleep(5)
            ele = driver.find_element_by_id('vImg')
            ele.screenshot('ele.png')
            #截取全屏后定位截图里验证码的位置，并重新裁剪保存
            # api识别部分
            img_path = "C:/Users/Downloads/ele.png"
            result = base64_api(uname='trevor', pwd='18078846977',img=img_path,typeid=3)
            # 输出识别出的验证码
            print("验证码识别：",result) 
            # 将验证码填入
            driver.find_element_by_id('vcode').send_keys(result)
            time.sleep(5)
            # 点击验证码的提交，然后开始下载
            driver.find_element_by_xpath('/html/body/div/form/dl/dd/button').click()
    except:
        print(f'{title}----已下载')
        continue


# ### pdf下载文献展示（截图）  
# 由于文章太多、文件太大，故不上传下载的pdf，仅做截图展示  
# ![pdf](https://gitee.com/yang_pei_jun/web_mining_cnki/raw/master/images/pdf_download.png)

# ## 抓取refworks

# In[171]:


# 第一次下载
pages = list(range(1,11))
print(pages)


# In[172]:


# 选中页面50篇 —> 翻页
def process_xuanzhong (pages):
    for p in pages:
        print (p,end='\t')
        全选 = driver.find_element_by_xpath('//*[@id="selectCheckAll1"]')
        全选.click()
        跳转 = driver.find_element_by_id('PageNext')
        跳转.click()
        time.sleep(20+20*random())


# In[173]:


process_xuanzhong (pages)


# In[174]:


# 导出与分析 导出refworks文件（.txt）[500篇]
element = driver.find_element_by_xpath('//i[@class="icon-d"]').click()


# In[175]:


# 导出文献
element = driver.find_element_by_xpath('//i[@class="icon-r"]').click()


# In[176]:


# 点击Refworks
element = driver.find_element_by_xpath('//a[@exporttype="Refworks"]').click()


# In[177]:


# 窗口切换
driver.switch_to_window(driver.window_handles[2])


# In[178]:


# 导出 .txt文件
element = driver.find_element_by_xpath('//i[@class="icon icon-export"]').click()


# In[179]:


# 查看txt
with open('CNKI-20210703155952231.txt', encoding='utf-8') as f:
    display(f.readlines())


# ## 数据可视化（VOSviewer--keywords_co-occurrence） 
# - 将导出的refworks文件导入vos中做可视化处理，结果如图：
# ![vos](https://gitee.com/yang_pei_jun/web_mining_cnki/raw/master/images/vos.png)  

# - 首次进行可视化处理时，发现有些词意思是一样的，如何我对同义词进行了处理，在data文件夹中的thesaurus_terms中添加了以下内容
# ![](https://gitee.com/yang_pei_jun/web_mining_cnki/raw/master/images/%E5%A4%84%E7%90%86%E5%90%8C%E4%B9%89%E8%AF%8D.png) 

# In[ ]:




